package vodresource

import (
	"ZHONGYIHANGYAN/bean/dbModel"
	"ZHONGYIHANGYAN/bean/request"
	"ZHONGYIHANGYAN/bean/response"
	global "ZHONGYIHANGYAN/business"
	"ZHONGYIHANGYAN/cfg"
	commUtils "ZHONGYIHANGYAN/commUtils"
	"fmt"
	"io"
	"net/http"
	netUrl "net/url"
	"os"
	"path/filepath"
	"strings"
	"time"
)

const TimeLayout = "2006-01-02 15:04:05"

// 获取点播资源列表
func (manage *VodResourceManage) GetVodResourceList(query *request.GetVodResourceListQuery) (response.PageData, error) {
	pageData := response.PageData{}

	db := manage.DataBase.DB()
	tx := db.Model(&dbModel.VodResource{})

	if query.AreaName != "" {
		tx = tx.Where("area_name like ?", "%"+query.AreaName+"%")
	}
	if query.ProgramName != "" {
		tx = tx.Where("program_name like ?", "%"+query.ProgramName+"%")
	}
	if query.StartTime != "" {
		tx = tx.Where("start_time >= ?", query.StartTime)
	}
	if query.EndTime != "" {
		tx = tx.Where("end_time <= ?", query.EndTime)
	}
	if query.DownloadStatus != nil {
		tx = tx.Where("download_status = ?", query.DownloadStatus)
	}

	// 获取总记录数
	var total int64
	if err := tx.Count(&total).Error; err != nil {
		return pageData, err
	}
	if total == 0 {
		pageData.List = []interface{}{}
		return pageData, nil
	}

	// 分页查询
	currentPage := query.CurrentPage
	numPerPage := query.NumPerPage
	if currentPage <= 0 {
		currentPage = 1
	}
	if numPerPage <= 0 {
		numPerPage = 50
	}
	offset := (currentPage - 1) * numPerPage
	tx = tx.Order("area_name ASC, program_name ASC").Limit(numPerPage).Offset(offset)

	var resourceList []response.GetVodResourceListResponseInfo
	if err := tx.Find(&resourceList).Error; err != nil {
		return pageData, err
	}

	pageData.CurrentPage = currentPage
	pageData.NumPerPage = numPerPage
	pageData.TotalCount = int(total)
	pageData.TotalPages = (pageData.TotalCount + numPerPage - 1) / numPerPage
	pageData.List = resourceList

	return pageData, nil
}

// 添加或修改点播资源
func (manage *VodResourceManage) AddOrUpdateVodResource(vodResource *request.AddOrUpdateVodResourceQuery) error {
	db := manage.DataBase.DB()
	isUpdate := vodResource.Id != ""

	if !isUpdate {
		resourceToCreate := dbModel.VodResource{
			Id:          commUtils.GenUUID(),
			AreaName:    vodResource.AreaName,
			ProgramName: vodResource.ProgramName,
			PreviewUrl:  vodResource.PreviewUrl,
		}
		// 在解引用指针前，必须检查它们是否为nil，避免panic
		if vodResource.SignalStatus != nil {
			resourceToCreate.SignalStatus = *vodResource.SignalStatus
		}
		if vodResource.DownloadStatus != nil {
			resourceToCreate.DownloadStatus = *vodResource.DownloadStatus
		}
		if vodResource.StartTime != "" {
			parsedStartTime, err := time.ParseInLocation(TimeLayout, vodResource.StartTime, global.CstZone)
			if err != nil {
				return fmt.Errorf("开始时间格式错误，请使用 'YYYY-MM-DD HH:MM:SS' 格式: %w", err)
			}
			resourceToCreate.StartTime = parsedStartTime
		}
		if vodResource.EndTime != "" {
			parsedEndTime, err := time.ParseInLocation(TimeLayout, vodResource.EndTime, global.CstZone)
			if err != nil {
				return fmt.Errorf("结束时间格式错误，请使用 'YYYY-MM-DD HH:MM:SS' 格式: %w", err)
			}
			resourceToCreate.EndTime = parsedEndTime
		}
		if err := db.Create(&resourceToCreate).Error; err != nil {
			return err
		}
	} else {
		idToUpdate := vodResource.Id
		updateData := map[string]interface{}{
			"area_name":    vodResource.AreaName,
			"program_name": vodResource.ProgramName,
			"preview_url":  vodResource.PreviewUrl,
		}
		// 安全处理指针
		if vodResource.SignalStatus != nil {
			updateData["signal_status"] = *vodResource.SignalStatus
		}
		if vodResource.DownloadStatus != nil {
			updateData["download_status"] = *vodResource.DownloadStatus
		}
		if vodResource.StartTime != "" {
			parsedStartTime, err := time.ParseInLocation(TimeLayout, vodResource.StartTime, global.CstZone)
			if err != nil {
				return fmt.Errorf("开始时间格式错误，请使用 'YYYY-MM-DD HH:MM:SS' 格式: %w", err)
			}
			updateData["start_time"] = parsedStartTime
		}
		if vodResource.EndTime != "" {
			parsedEndTime, err := time.ParseInLocation(TimeLayout, vodResource.EndTime, global.CstZone)
			if err != nil {
				return fmt.Errorf("结束时间格式错误，请使用 'YYYY-MM-DD HH:MM:SS' 格式: %w", err)
			}
			updateData["end_time"] = parsedEndTime
		}
		if err := manage.updateVodResourceFields(idToUpdate, updateData); err != nil {
			return err
		}
	}
	return nil
}

// 删除点播资源
func (manage *VodResourceManage) DeleteVodResource(vodResourceIds []string) error {
	if len(vodResourceIds) == 0 {
		return nil
	}

	db := manage.DataBase.DB()
	result := db.Where("id IN ?", vodResourceIds).Delete(&dbModel.VodResource{})
	if result.Error != nil {
		return result.Error
	}
	if result.RowsAffected == 0 {
		return fmt.Errorf("没有找到要删除的记录，ID列表可能无效或记录已被删除")
	}
	return nil
}


// 获取点播资源详情
func (manage *VodResourceManage) GetVodResourceDetail(query *request.GetVodResourceDetailQuery) (*response.GetVodResourceDetailResponse, error) {
	db := manage.DataBase.DB()
	
	var vodResource dbModel.VodResource
	if err := db.Where("id = ?", query.VodResourceId).First(&vodResource).Error; err != nil {
		return nil, fmt.Errorf("获取点播资源详情失败：%v", err)
	}
	
	response := &response.GetVodResourceDetailResponse{
		Id:           vodResource.Id,
		AreaName:     vodResource.AreaName,
		ProgramName:  vodResource.ProgramName,
		SignalStatus: &vodResource.SignalStatus,
		PreviewUrl:   vodResource.PreviewUrl,
		StartTime:    vodResource.StartTime.Format(TimeLayout),
		EndTime:      vodResource.EndTime.Format(TimeLayout),
		DownloadStatus: vodResource.DownloadStatus,
	}
	
	return response, nil
}

// 下载资源
func (manage *VodResourceManage) DownloadVodResource(query *request.DownloadVodResourceQuery) (*response.DownloadVodResourceResponse, error) {
	// 验证输入参数
	if query.VideoUrl == "" {
		return nil, fmt.Errorf("视频资源地址不能为空")
	}
	if query.VodResourceId == "" {
		return nil, fmt.Errorf("资源ID不能为空")
	}
	
	// 处理URL协议
	videoUrl := normalizeURL(query.VideoUrl)
	
	// 获取下载目录配置
	downloadDir := cfg.Sys.DownloadDir
	if downloadDir == "" {
		return nil, fmt.Errorf("没有配置文件存放路径，请在配置文件中设置downloadDir")
	}
	
	// 确保目录路径以正确的分隔符结尾
	downloadDir = filepath.Clean(downloadDir)
	
	// 检查配置的路径是否真实存在
	if _, err := os.Stat(downloadDir); os.IsNotExist(err) {
		return nil, fmt.Errorf("没有找到文件存放路径: %s", downloadDir)
	}
	
	// 从URL中提取文件名
	fileName := extractFileName(videoUrl)
	if fileName == "" {
		// 如果无法从URL提取文件名，使用时间戳生成
		fileName = fmt.Sprintf("video_%d.mp4", time.Now().Unix())
	}
	
	// 完整的文件路径
	filePath := filepath.Join(downloadDir, fileName)
	
	// 创建HTTP客户端，设置超时
	client := &http.Client{
		Timeout: 30 * time.Minute, // 设置30分钟超时，适合大文件下载
	}
	
	// 发起HTTP GET请求
	resp, err := client.Get(videoUrl)
	if err != nil {
		return nil, fmt.Errorf("下载视频失败: %v", err)
	}
	defer resp.Body.Close()
	
	// 检查HTTP状态码
	if resp.StatusCode != http.StatusOK {
		return nil, fmt.Errorf("下载视频失败，HTTP状态码: %d", resp.StatusCode)
	}
	
	// 创建目标文件
	file, err := os.Create(filePath)
	if err != nil {
		return nil, fmt.Errorf("创建文件失败: %v", err)
	}
	defer file.Close()
	
	// 使用io.Copy复制数据，这样可以处理大文件
	_, err = io.Copy(file, resp.Body)
	if err != nil {
		// 如果下载失败，删除不完整的文件
		os.Remove(filePath)
		return nil, fmt.Errorf("保存视频文件失败: %v", err)
	}
	
	// 记录下载成功日志
	fmt.Printf("视频下载成功，保存路径: %s\n", filePath)
	
	// 生成HTTP访问地址
	httpUrl := buildHttpUrl(downloadDir, fileName)
	
	// 更新数据库记录
	if err := manage.updateVodResourceAfterDownload(query.VodResourceId, httpUrl); err != nil {
		// 下载成功但数据库更新失败，记录警告日志但不返回错误
		fmt.Printf("警告：下载成功但更新数据库失败: %v\n", err)
	}
	
	return &response.DownloadVodResourceResponse{
		PreviewUrl: httpUrl,
	}, nil
}

// extractFileName 从URL中提取文件名
func extractFileName(url string) string {
	// 解析URL
	u, err := netUrl.Parse(url)
	if err != nil {
		return ""
	}
	
	// 获取路径的最后部分作为文件名
	_, fileName := filepath.Split(u.Path)
	
	// 如果文件名为空或者没有扩展名，返回空字符串
	if fileName == "" || !strings.Contains(fileName, ".") {
		return ""
	}
	
	return fileName
}

// normalizeURL 标准化URL，确保有正确的协议前缀
func normalizeURL(url string) string {
	// 去除首尾空白字符
	url = strings.TrimSpace(url)
	
	// 如果URL以"//"开头，添加https协议
	if strings.HasPrefix(url, "//") {
		return "https:" + url
	}
	
	// 如果URL没有协议前缀，添加https://
	if !strings.HasPrefix(url, "http://") && !strings.HasPrefix(url, "https://") {
		return "https://" + url
	}
	
	return url
}

// buildHttpUrl 构建HTTP访问地址
func buildHttpUrl(downloadDir, fileName string) string {
	// 获取项目根目录的绝对路径
	projectRoot, err := os.Getwd()
	if err != nil {
		projectRoot = ""
	}
	
	// 提取相对路径
	relativePath := extractRelativePath(downloadDir, projectRoot)
	
	// 组成HTTP地址：http://ip:port/relativePath/fileName
	httpUrl := fmt.Sprintf("http://%s:%d/%s/%s", 
		cfg.Sys.LocalIp, 
		cfg.Sys.WebPort, 
		relativePath, 
		fileName)
	
	return httpUrl
}

// extractRelativePath 从绝对路径中提取相对于项目根目录的路径
func extractRelativePath(absolutePath, projectRoot string) string {
	// 标准化路径
	absolutePath = filepath.Clean(absolutePath)
	projectRoot = filepath.Clean(projectRoot)
	
	// 如果下载目录在项目根目录内，提取相对路径
	if strings.HasPrefix(absolutePath, projectRoot) {
		relativePath := strings.TrimPrefix(absolutePath, projectRoot)
		relativePath = strings.TrimPrefix(relativePath, string(filepath.Separator))
		// 将Windows路径分隔符转换为URL路径分隔符
		relativePath = strings.ReplaceAll(relativePath, "\\", "/")
		return relativePath
	}
	
	// 如果不在项目根目录内，返回目录名
	return filepath.Base(absolutePath)
}

//  通用的字段更新方法
func (manage *VodResourceManage) updateVodResourceFields(vodResourceId string, updateData map[string]interface{}) error {
	db := manage.DataBase.DB()
	
	result := db.Model(&dbModel.VodResource{}).Where("id = ?", vodResourceId).Updates(updateData)
	if result.Error != nil {
		return fmt.Errorf("更新数据库失败: %v", result.Error)
	}
	
	// 检查是否有记录被更新
	if result.RowsAffected == 0 {
		return fmt.Errorf("未找到ID为 %s 的资源记录", vodResourceId)
	}
	
	return nil
}

//  下载完成后更新数据库记录
func (manage *VodResourceManage) updateVodResourceAfterDownload(vodResourceId, previewUrl string) error {
	updateData := map[string]interface{}{
		"preview_url":     previewUrl,
		"download_status": 1, // 1-已下载
	}
	
	if err := manage.updateVodResourceFields(vodResourceId, updateData); err != nil {
		return err
	}
	
	fmt.Printf("资源记录更新成功，ID: %s, PreviewUrl: %s\n", vodResourceId, previewUrl)
	return nil
}

